package com.haiyi.test.dtmoths;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Base64.Decoder;
import java.util.Base64.Encoder;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import org.springframework.util.StringUtils;

public class EncryptUtil
{
  private EncryptUtil()
  {
    throw new UnsupportedOperationException("cannot be instantiated");
  }
  
  private static String UTF8 = "utf-8";
  public static final int MD5_TYPE_IO = 0;
  public static final int MD5_TYPE_NIO = 1;
  public static final String SHA224 = "sha-224";
  public static final String SHA256 = "sha-256";
  public static final String SHA384 = "sha-384";
  public static final String SHA512 = "sha-512";
  public static final int RSA_PUBLIC_ENCRYPT = 0;
  public static final int RSA_PUBLIC_DECRYPT = 1;
  public static final int RSA_PRIVATE_ENCRYPT = 2;
  public static final int RSA_PRIVATE_DECRYPT = 3;
  
  private static String parseByte2HexStr(byte[] buf)
  {
    StringBuilder sb = new StringBuilder();
    for (byte b : buf)
    {
      String hex = Integer.toHexString(b & 0xFF);
      if (hex.length() == 1) {
        hex = '0' + hex;
      }
      sb.append(hex.toUpperCase());
    }
    return sb.toString();
  }
  
  private static byte[] parseHexStr2Byte(String hexStr)
  {
    if (hexStr.length() < 1) {
      return null;
    }
    byte[] result = new byte[hexStr.length() / 2];
    for (int i = 0; i < hexStr.length() / 2; i++)
    {
      int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
      int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
      result[i] = ((byte)(high * 16 + low));
    }
    return result;
  }
  
  public static String md5(String string, String slat)
  {
    if (StringUtils.isEmpty(string)) {
      return "";
    }
    try
    {
      MessageDigest md5 = MessageDigest.getInstance("MD5");
      byte[] bytes = md5.digest((string + slat).getBytes());
      StringBuilder buffer = new StringBuilder();
      for (byte b : bytes)
      {
        String temp = Integer.toHexString(b & 0xFF);
        if (temp.length() == 1) {
          temp = "0" + temp;
        }
        buffer.append(temp);
      }
      return buffer.toString();
    }
    catch (NoSuchAlgorithmException e)
    {
      e.printStackTrace();
    }
    return "";
  }
  
  public static String md5(String string)
  {
    return StringUtils.isEmpty(string) ? "" : md5(string, "");
  }
  
  public static String md5(File file, int style)
  {
    if ((file == null) || (!file.isFile()) || (!file.exists())) {
      return "";
    }
    FileInputStream in = null;
    StringBuilder builder = new StringBuilder();
    byte[] buffer = new byte[8192];
    try
    {
      in = new FileInputStream(file);
      MessageDigest md5 = MessageDigest.getInstance("MD5");
      byte[] bytes = md5.digest();
      if (style == 0)
      {
        int len;
        while ((len = in.read(buffer)) != -1) {
          md5.update(buffer, 0, len);
        }
      }
      MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, 0L, file
        .length());
      md5.update(byteBuffer);
      for (byte b : bytes)
      {
        String temp = Integer.toHexString(b & 0xFF);
        if (temp.length() == 1) {
          temp = "0" + temp;
        }
        builder.append(temp);
      }
      if (null != in) {
        try
        {
          in.close();
        }
        catch (IOException e)
        {
          e.printStackTrace();
        }
      }
      return builder.toString();
    }
    catch (Exception e)
    {
      e.printStackTrace();
      if (null != in) {
        try
        {
          in.close();
        }
        catch (IOException ee)
        {
        	ee.printStackTrace();
        }
      }
    }
    finally
    {
      if (null != in) {
        try
        {
          in.close();
        }
        catch (IOException e)
        {
          e.printStackTrace();
        }
      }
    }
	return UTF8;
  }
  
  public static String md5(String string, int times)
  {
    if (StringUtils.isEmpty(string)) {
      return "";
    }
    String md5 = md5(string);
    for (int i = 0; i < times; i++) {
      md5 = md5(md5);
    }
    return md5;
  }
  
  public static String base64EncodeStr(String string)
    throws UnsupportedEncodingException
  {
    if (StringUtils.isEmpty(string)) {
      return "";
    }
    return Base64.getEncoder().encodeToString(string.getBytes(UTF8));
  }
  
  public static String base64DecodedStr(String string)
    throws UnsupportedEncodingException
  {
    if (StringUtils.isEmpty(string)) {
      return "";
    }
    return new String(Base64.getDecoder().decode(string.getBytes(UTF8)), UTF8);
  }
  
  public static String base64EncodeFile(File file)
  {
    if (null == file) {
      return "";
    }
    try
    {
      FileInputStream inputFile = new FileInputStream(file);
      byte[] buffer = new byte[(int)file.length()];
      inputFile.read(buffer);
      inputFile.close();
      return Base64.getEncoder().encodeToString(buffer);
    }
    catch (IOException e)
    {
      e.printStackTrace();
    }
    return "";
  }
  
  public static File base64DecodedFile(String filePath, String code)
  {
    if ((StringUtils.isEmpty(filePath)) || (StringUtils.isEmpty(code))) {
      return null;
    }
    File desFile = new File(filePath);
    try
    {
      byte[] decodeBytes = Base64.getDecoder().decode(code.getBytes());
      FileOutputStream fos = new FileOutputStream(desFile);
      fos.write(decodeBytes);
      fos.close();
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
    return desFile;
  }
  
  public static String aes(String content, String password, int type)
  {
    try
    {
      KeyGenerator generator = KeyGenerator.getInstance("AES");
      SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
      secureRandom.setSeed(password.getBytes());
      generator.init(128, secureRandom);
      SecretKey secretKey = generator.generateKey();
      byte[] enCodeFormat = secretKey.getEncoded();
      SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
      Cipher cipher = Cipher.getInstance("AES");
      cipher.init(type, key);
      if (type == 1)
      {
        byte[] byteContent = content.getBytes("utf-8");
        return parseByte2HexStr(cipher.doFinal(byteContent));
      }
      byte[] byteContent = parseHexStr2Byte(content);
      return new String(cipher.doFinal(byteContent));
    }
    catch (NoSuchAlgorithmException|BadPaddingException|IllegalBlockSizeException|UnsupportedEncodingException|InvalidKeyException|NoSuchPaddingException e)
    {
      e.printStackTrace();
    }
    return null;
  }
  
  public static String des(String content, String password, int type)
  {
    try
    {
      SecureRandom random = new SecureRandom();
      DESKeySpec desKey = new DESKeySpec(password.getBytes());
      SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
      Cipher cipher = Cipher.getInstance("DES");
      cipher.init(type, keyFactory.generateSecret(desKey), random);
      if (type == 1)
      {
        byte[] byteContent = content.getBytes("utf-8");
        return parseByte2HexStr(cipher.doFinal(byteContent));
      }
      byte[] byteContent = parseHexStr2Byte(content);
      return new String(cipher.doFinal(byteContent));
    }
    catch (NoSuchAlgorithmException|BadPaddingException|IllegalBlockSizeException|UnsupportedEncodingException|InvalidKeyException|NoSuchPaddingException|InvalidKeySpecException e)
    {
      e.printStackTrace();
    }
    return null;
  }
  
  public static String sha(String string, String type)
  {
    if (StringUtils.isEmpty(string)) {
      return "";
    }
    if (StringUtils.isEmpty(type)) {
      type = "sha-256";
    }
    try
    {
      MessageDigest md5 = MessageDigest.getInstance(type);
      byte[] bytes = md5.digest(string.getBytes());
      StringBuilder builder = new StringBuilder();
      for (byte b : bytes)
      {
        String temp = Integer.toHexString(b & 0xFF);
        if (temp.length() == 1) {
          temp = "0" + temp;
        }
        builder.append(temp);
      }
      return builder.toString();
    }
    catch (NoSuchAlgorithmException e)
    {
      e.printStackTrace();
    }
    return "";
  }
  
  public static Map<String, Object> getKeyPair()
    throws Exception
  {
    KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
    keyPairGen.initialize(1024, new SecureRandom());
    
    KeyPair keyPair = keyPairGen.generateKeyPair();
    RSAPublicKey publicKey = (RSAPublicKey)keyPair.getPublic();
    RSAPrivateKey privateKey = (RSAPrivateKey)keyPair.getPrivate();
    
    Map<String, Object> keyMap = new HashMap(2);
    keyMap.put("RSAPublicKey", publicKey);
    keyMap.put("RSAPrivateKey", privateKey);
    return keyMap;
  }
  
  public static String getKey(Map<String, Object> keyMap, boolean isPublicKey)
  {
    Key key = (Key)keyMap.get(isPublicKey ? "RSAPublicKey" : "RSAPrivateKey");
    return new String(Base64.getEncoder().encode(key.getEncoded()));
  }
  
  public static String rsa(byte[] data, String string, int type)
    throws Exception
  {
    byte[] keyBytes = Base64.getDecoder().decode(string);
    

    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    Key key;
    if ((type == 0) || (type == 1))
    {
      X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
      key = keyFactory.generatePublic(x509KeySpec);
    }
    else
    {
      PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
      key = keyFactory.generatePrivate(pkcs8KeySpec);
    }
    Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
    if ((type == 0) || (type == 2))
    {
      cipher.init(1, key);
      byte[] output = cipher.doFinal(data);
      return DatatypeConverter.printBase64Binary(output);
    }
    cipher.init(2, key);
    byte[] output = cipher.doFinal(data);
    return new String(output);
  }
  
  public static String base64ToStr(byte[] b)
  {
    return DatatypeConverter.printBase64Binary(b);
  }
  
  public static byte[] strToBase64Binary(String str)
  {
    return DatatypeConverter.parseBase64Binary(str);
  }
}

